import subprocess
import math
import statistics
from openpyxl import Workbook, load_workbook
import requests
import time

# 默认配置
DEFAULT_MIN_REPLICAS = 1
DEFAULT_CPU_REQUEST = 100.0  # 毫核
# TARGET_CPU_PERCENTAGE = 80
TARGET_CPU_PERCENTAGE = 50
MAX_REPLICAS = 5

# 获取就绪副本数，只统计业务容器
def get_ready_replicas(app_name, namespace, retries=3, delay=2):
    """
    获取指定微服务的业务容器的 ready 副本数。
    """
    for attempt in range(retries):
        try:
            command = (
                f"kubectl get pods -n {namespace} -l app={app_name} "
                f"-o=jsonpath='{{range .items[*]}}{{range .status.containerStatuses[?(@.name==\"{app_name}\")]}}{{.ready}} {{end}}{{end}}'"
            )
            container_ready_statuses = subprocess.check_output(command, shell=True).decode('utf-8').strip().split()
            ready_count = sum(1 for ready in container_ready_statuses if ready.lower() == "true")
            print(f"[DEBUG] Ready replicas for {app_name} (Attempt {attempt+1}): {ready_count}")
            return ready_count
        except subprocess.CalledProcessError as e:
            print(f"[ERROR] Attempt {attempt+1} failed to fetch ready replicas: {e}")
            time.sleep(delay)
    print(f"[ERROR] Failed to fetch ready replicas for {app_name} after {retries} retries.")
    return 0

# 获取期望副本数
def get_desired_replicas(app_name, namespace):
    """
    获取 Deployment 的期望副本数。
    """
    try:
        command = f"kubectl get deployment {app_name} -n {namespace} -o=jsonpath='{{.spec.replicas}}'"
        result = subprocess.check_output(command, shell=True).decode('utf-8').strip()
        desired_replicas = int(result)
        print(f"[DEBUG] Desired replicas for {app_name}: {desired_replicas}")
        return desired_replicas
    except Exception as e:
        print(f"[ERROR] Failed to fetch desired replicas for {app_name}: {e}")
        return DEFAULT_MIN_REPLICAS
def get_cpu_usage(app_name, namespace, retries=3, timeout=10):
    """
    获取指定微服务的平均 CPU 使用率（毫核）。如果获取失败，将尝试重试。
    """
    cpu_query = f'rate(container_cpu_usage_seconds_total{{namespace="{namespace}", pod=~"{app_name}-.*", container="{app_name}"}}[1m])'
    
    for attempt in range(retries):
        try:
            # 发送请求
            response = requests.get(f"http://10.10.100.40:30090/api/v1/query?query={cpu_query}", timeout=timeout)
            response.raise_for_status()  # 如果状态码不是200，会抛出异常
            cpu_data = response.json().get('data', {}).get('result', [])
            
            if not cpu_data:
                print(f"[WARN] No data found for {app_name} in namespace {namespace}.")
                return 0  # 如果没有数据，返回 0
            
            # 获取 CPU 使用率并计算平均值
            cpu_values = [float(x['value'][1]) * 1000 for x in cpu_data]  # 转换为毫核
            if cpu_values:
                current_cpu = math.ceil(statistics.mean(cpu_values))  # 计算平均值
                print(f"[DEBUG] Average CPU usage for {app_name}: {current_cpu}m")
                return current_cpu
            else:
                print(f"[WARN] No valid CPU data for {app_name}.")
                return 0

        except requests.exceptions.Timeout:
            print(f"[ERROR] Timeout occurred while fetching CPU usage for {app_name} (attempt {attempt + 1}).")
        except requests.exceptions.RequestException as e:
            print(f"[ERROR] Request error for {app_name} (attempt {attempt + 1}): {e}")
        except Exception as e:
            print(f"[ERROR] Unexpected error while fetching CPU usage for {app_name} (attempt {attempt + 1}): {e}")
        
        # 等待一定时间后重试
        time.sleep(2)  # 休眠2秒后重试
    
    # 如果所有重试都失败，返回 0
    print(f"[ERROR] Failed to fetch CPU usage for {app_name} after {retries} attempts.")
    return 0

# Monitor 组件：收集监控数据
def Monitor(app_name, namespace="boutique"):
    """
    收集微服务的监控数据。
    """
    current_replicas = get_ready_replicas(app_name, namespace)
    desired_replicas = get_desired_replicas(app_name, namespace)
    current_cpu = get_cpu_usage(app_name, namespace)
    return app_name, desired_replicas, current_replicas, current_cpu, TARGET_CPU_PERCENTAGE, DEFAULT_CPU_REQUEST, MAX_REPLICAS, DEFAULT_MIN_REPLICAS

# Analyze 组件：分析监控数据并生成扩缩容决策
def Analyse(desired_replicas, current_replicas, current_cpu, target_cpu, cpu_request, min_replicas):
    """
    分析数据并生成扩缩容决策。
    """
    cpu_percentage = (current_cpu / cpu_request) * 100 if cpu_request > 0 else 0
    print(f"[DEBUG] CPU Percentage: {cpu_percentage:.2f}%")

    desired_replica = max(math.ceil(current_replicas * (cpu_percentage / target_cpu)), min_replicas)
    print(f"[DEBUG] Calculated desired replicas: {desired_replica}")

    scaling_action = "scale up" if desired_replica > current_replicas else ("scale down" if desired_replica < current_replicas else "no scale")
    print(f"[DEBUG] Scaling action: {scaling_action}")
    return cpu_percentage, scaling_action, desired_replica

# 主函数：执行扩缩容逻辑并保存结果
def currencyservice(Test_Time, folder_name):
    """
    管理 currencyservice 微服务的扩缩容逻辑。
    """
    app_name = "currencyservice"
    app_name, desired_replicas, current_replicas, current_cpu, target_cpu, cpu_request, max_replicas, min_replicas = Monitor(app_name)
    cpu_percentage, scaling_action, desired_replica = Analyse(desired_replicas, current_replicas, current_cpu, target_cpu, cpu_request, min_replicas)

    file_path = f"/root/wmxstudy/Smart_HPA/Smart_HPA_Codebase/Knowledge_Base/{folder_name}/{app_name}.xlsx"
    try:
        workbook = load_workbook(file_path)
    except FileNotFoundError:
        workbook = Workbook()
        workbook.save(file_path)
        workbook = load_workbook(file_path)

    sheet = workbook.active
    sheet.cell(row=1, column=1, value="Test Time (sec)")
    sheet.cell(row=1, column=2, value="CPU Usage Percentage")
    sheet.cell(row=1, column=3, value="Current Replicas")
    sheet.cell(row=1, column=4, value="Desired Replicas")
    sheet.cell(row=1, column=5, value="Max.Replicas")
    sheet.cell(row=1, column=6, value="Scaling Action")
    
    Test_Time_row_length = len(sheet['A']) + 1
    CPU_usage_row_length = len(sheet['B']) + 1
    current_replica_row_length = len(sheet['C']) + 1
    desired_replica_row_length = len(sheet['D']) + 1
 
    sheet[f'A{Test_Time_row_length}'] = Test_Time
    sheet[f'B{CPU_usage_row_length}'] = cpu_percentage
    sheet[f'C{current_replica_row_length}'] = current_replicas
    sheet[f'D{desired_replica_row_length}'] = desired_replica

    workbook.save(file_path)
    workbook.close()  # Close the workbook
    
    return {
        
        "app_name": app_name,               # 微服务名称
        "scaling_action": scaling_action,   # 伸缩决策
        "desired_replicas": desired_replica,   # 期望副本数
        "current_replicas": current_replicas,  # 当前副本数
        "cpu_request": cpu_request,           # cpu
        "max_replica": max_replicas           # 最大副本数决策
    }

if __name__ == "__main__":
    TEST_TIME = 60
    FOLDER_NAME = "50"
    result = currencyservice(TEST_TIME, FOLDER_NAME)
    print(result)
